package ds

type SinglyLinkedNode[T comparable] struct {
	Val T
	Next *SinglyLinkedNode[T]
}

func InitializeSinglyLinkedNode[T comparable](value T, next *SinglyLinkedNode[T]) *SinglyLinkedNode[T] {
	return &SinglyLinkedNode[T]{
		Val: value,
		Next: next,
	}
}

func (node *SinglyLinkedNode[T]) ToList() []T {
	result := make([]T, 0)
	for node != nil {
		result = append(result, node.Val)
		node = node.Next
	}
	return result
}

func BuildSinglyLinkedList[T comparable](values []T) *SinglyLinkedNode[T] {
	sentinel := &SinglyLinkedNode[T]{}
	pointer := sentinel

	for _, v := range values {
		pointer.Next = &SinglyLinkedNode[T]{Val: v}
		pointer = pointer.Next
	}

	return sentinel.Next
}

func (node *SinglyLinkedNode[T]) Length() int {
	count := 0
	for node != nil {
		count += 1
		node = node.Next
	}
	return count
}

type DoublyLinkedNode[T comparable] struct {
	Val T
	Next, Previous *DoublyLinkedNode[T]
}

func BuildDoublyLinkedList[T comparable](values []T) *DoublyLinkedNode[T] {
	sentinel := &DoublyLinkedNode[T]{}
	pointer := sentinel

	for _, v := range values {
		previous := pointer
		pointer.Next = &DoublyLinkedNode[T]{Val: v}
		pointer.Previous = previous
	}
	
	return sentinel.Next
}

func (node *DoublyLinkedNode[T]) ToList(reverse bool) []T {
	result := make([]T, 0)

	if reverse {
		for node != nil && node.Previous != nil {
			result = append(result, node.Val)
			node = node.Previous
		}
		return result
	}

	for node != nil && node.Next != nil {
		result = append(result, node.Val)
		node = node.Next
	}
	return result
}
